<template>
  <div @click.prevent="fileBtnClick" v-bind="$attrs" class="file-upload-container">
    <slot v-if="filesStates === 'loading'" name="loading">
      <button class="btn btn-primary" disabled>正在上传...</button>
    </slot>
    <slot v-else-if="filesStates === 'success'" name="success" :uploadedData="uploadedData">
      <button class="btn btn-primary">上传成功</button>
    </slot>
    <slot v-else-if="filesStates === 'error'" name="error">
      <button class="btn btn-primary">上传出错</button>
    </slot>
    <slot v-else name="default">
      <button class="btn btn-primary">点击上传</button>
    </slot>
  </div>
  <input type="file" name="fileOne" ref="fileInput" class="d-none file-input" @change="handleFileChange">
</template>

<script lang="ts">
import { defineComponent, ref, PropType, watch } from 'vue'
// import { axiosInstance } from '../axiosDefaults'
import axios from 'axios'
type filesType = 'ready' | 'loading' | 'success' | 'error'
type filesFunction = (file: File) => boolean
export default defineComponent({
  name: 'Uploader',
  props: {
    action: {
      type: String,
      required: true
    },
    beforeUpData: {
      type: Function as PropType<filesFunction>
    },
    uploaded: {
      type: Object
    }
  },
  inheritAttrs: false,
  emits: ['fileUploaded', 'uploadedError'],
  setup (props, context) {
    const uploadedData = ref(props.uploaded)
    // 上传文件状态
    const filesStates = ref<filesType>(props.uploaded ? 'success' : 'ready')

    watch(() => props.uploaded, newValue => {
      if (newValue) {
        filesStates.value = 'success'
        uploadedData.value = newValue.data.url
      }
    })
    // 上传Input 的 dom
    const fileInput = ref<null | HTMLInputElement>(null)
    const fileBtnClick = () => { // 按钮的点击事件
      if (fileInput.value) {
        fileInput.value.click() // 使用click()点击api 模拟点击
      }
    }
    // 上传事件
    const handleFileChange = async (e: Event) => {
      const target = e.target as HTMLInputElement
      const files = target.files // 获取上传文件的list
      if (files) {
        const filesArr = Array.from(files)
        if (props.beforeUpData) { // 上传类型的限制
          const result = props.beforeUpData(filesArr[0])
          if (!result) {
            filesStates.value = 'error'
            return
          }
        }
        filesStates.value = 'loading'
        // 把fileList 转换成一个数组
        // 实例化表单
        const formData = new FormData()
        // 把上传的文件传入表单中
        formData.append('file', filesArr[0])
        // const firstFiles = filesArr[0]
        // 发送请求把文件传给后端
        await axios.post(props.action, formData, {
          headers: {
            'Content-Type': 'multipart/from-data'
          }
        }).then(res => {
          context.emit('fileUploaded', res.data)
          uploadedData.value = res.data.data.url
          // 把按钮状态改变为成功
          filesStates.value = 'success'
        }).catch(error => {
          console.log(error)
          // 把状态改变成错误
          filesStates.value = 'error'
        }).finally(() => {
          // 把Input 节点上的value值设置为空
          if (fileInput.value) {
            fileInput.value.value = ''
          }
        })
      }
    }
    return { fileBtnClick, fileInput, filesStates, handleFileChange, uploadedData }
  }
})
</script>
